#include "RenderObject.h"
#include "StringUtility.h"


using namespace Util;

namespace Renderer
{
RenderObject::RenderObject() : iFirstChild(0),
							 iLastChild(0),
							 iNextSibling(0),
							 iPreSibling(0),
							 iParent(0),
							 iChildNodeCount(0),
							 iHtmlStyle(),
							 iNode(0)
{

}

RenderObject::~RenderObject()
{

}

RenderObject* RenderObject::CreateRenderObjectL(Node* aNode,const TDesC& aDes)
	{
	if(aNode->NodeType() != Node::NTElement)
		return NULL;
		
	RenderObject* pRetRO = new(ELeave) RenderObject;
	pRetRO->SetBindNode(aNode);
	
	_LIT(KMargin,"margin");
	_LIT(KPadding,"padding");
	_LIT(KBorder,"border");
	_LIT(KWidth,"width");
	_LIT(KHeight,"height");
	
	CStringUtility* strUtil = CStringUtility::NewL(aDes);
	CleanupStack::PushL(strUtil);

	while(!strUtil->Eof())
	{
		TBuf<1> buf = _L(";");
		TPtrC ptr = strUtil->NextToken(buf);
		if(ptr.Ptr())
		{
			if(ptr.Find(KMargin) != KErrNotFound)
				_parseMarginL(ptr,pRetRO);
			else if(ptr.Find(KPadding) != KErrNotFound)
				_parsePaddingL(ptr,pRetRO);
			else if(ptr.Find(KBorder) != KErrNotFound)
				_parseBorderL(ptr,pRetRO);
			else if(ptr.Find(KWidth) != KErrNotFound)
				_parseWidth(ptr,pRetRO);
			else if(ptr.Find(KHeight) != KErrNotFound)
				_parseHeight(ptr,pRetRO);
		}
	}

	CleanupStack::PopAndDestroy(1);
	
	return pRetRO;
	}

void RenderObject::_parseMarginL(const TDesC& aDes,RenderObject* iRenderObj)
	{
		HtmlStyle* aStyle = iRenderObj->GetHtmlStyle();
		if(!aStyle)
			return;
	
		TBuf<16> buf = _L("margin-left:");
		TInt pos = 0;
		if((pos =aDes.Find(buf)) != KErrNotFound)
		{
			aStyle->iMargin.SetLeft(aDes.Mid(pos+buf.Length()));
			return;
		}

		buf = _L("margin-right:");
		if((pos =aDes.Find(buf)) != KErrNotFound)
		{
			aStyle->iMargin.SetRight(aDes.Mid(pos+buf.Length()));
			return;
		}

		buf = _L("margin-top:");
		if((pos =aDes.Find(buf)) != KErrNotFound)
		{
			aStyle->iMargin.SetTop(aDes.Mid(pos+buf.Length()));
			return;
		}

		buf = _L("margin-bottom:");
		if((pos =aDes.Find(buf)) != KErrNotFound)
		{
			aStyle->iMargin.SetBottom(aDes.Mid(pos+buf.Length()));
			return;
		}

		buf = _L("margin:");
		if((pos =aDes.Find(buf)) != KErrNotFound)
		{
			CStringUtility* strUtil = CStringUtility::NewL(aDes.Mid(pos+buf.Length()));
			CleanupStack::PushL(strUtil);
			
			TBuf<1> sel = _L(" ");
			CDesCArray* marginArray = new(ELeave) CDesCArraySeg(4);
			CleanupStack::PushL(marginArray);
			
			while (!strUtil->Eof())
			{
				TPtrC ptr = strUtil->NextToken(sel);

				marginArray->AppendL(ptr);
			}

			if(marginArray->MdcaCount() == 1)
			{
				aStyle->iMargin.SetLeft(marginArray->MdcaPoint(0));
				aStyle->iMargin.SetRight(marginArray->MdcaPoint(0));
				aStyle->iMargin.SetTop(marginArray->MdcaPoint(0));
				aStyle->iMargin.SetBottom(marginArray->MdcaPoint(0));
			}
			else if(marginArray->Count() == 2)
			{
				aStyle->iMargin.SetTop(marginArray->MdcaPoint(0));
				aStyle->iMargin.SetRight(marginArray->MdcaPoint(1));
				aStyle->iMargin.SetBottom(marginArray->MdcaPoint(0));
				aStyle->iMargin.SetLeft(marginArray->MdcaPoint(1));
			}
			else if(marginArray->Count() == 3)
			{
				aStyle->iMargin.SetTop(marginArray->MdcaPoint(0));
				aStyle->iMargin.SetRight(marginArray->MdcaPoint(1));
				aStyle->iMargin.SetBottom(marginArray->MdcaPoint(2));
				aStyle->iMargin.SetLeft(marginArray->MdcaPoint(1));
			}
			else if(marginArray->Count() == 4)
			{
				aStyle->iMargin.SetTop(marginArray->MdcaPoint(0));
				aStyle->iMargin.SetRight(marginArray->MdcaPoint(1));
				aStyle->iMargin.SetBottom(marginArray->MdcaPoint(2));
				aStyle->iMargin.SetLeft(marginArray->MdcaPoint(3));
			}

			CleanupStack::PopAndDestroy(2);

		}
	}

void RenderObject::_parsePaddingL(const TDesC& aDes,RenderObject* iRenderObj)
{
	HtmlStyle* aStyle = iRenderObj->GetHtmlStyle();
	if(!aStyle)
		return;

	TBuf<16> buf = _L("padding-left:");
	TInt pos = 0;
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iPadding.SetLeft(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("padding-right:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iPadding.SetRight(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("padding-top:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iPadding.SetTop(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("padding-bottom:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iPadding.SetBottom(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("padding:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		CStringUtility* strUtil = CStringUtility::NewL(aDes.Mid(pos+buf.Length()));
		CleanupStack::PushL(strUtil);

		TBuf<1> sel = _L(" ");
		CDesCArray* marginArray = new(ELeave) CDesCArraySeg(4);
		CleanupStack::PushL(marginArray);
		
		while (!strUtil->Eof())
		{
			TPtrC ptr = strUtil->NextToken(sel);
			marginArray->AppendL(ptr);
		}

		if(marginArray->MdcaCount() == 1)
		{
			aStyle->iPadding.SetLeft((*marginArray)[0]);
			aStyle->iPadding.SetRight((*marginArray)[0]);
			aStyle->iPadding.SetTop((*marginArray)[0]);
			aStyle->iPadding.SetBottom((*marginArray)[0]);
		}
		else if(marginArray->MdcaCount() == 2)
		{
			aStyle->iPadding.SetTop((*marginArray)[0]);
			aStyle->iPadding.SetRight((*marginArray)[1]);
			aStyle->iPadding.SetBottom((*marginArray)[0]);
			aStyle->iPadding.SetLeft((*marginArray)[1]);
		}
		else if(marginArray->MdcaCount() == 3)
		{
			aStyle->iPadding.SetTop((*marginArray)[0]);
			aStyle->iPadding.SetRight((*marginArray)[1]);
			aStyle->iPadding.SetBottom((*marginArray)[2]);
			aStyle->iPadding.SetLeft((*marginArray)[1]);
		}
		else if(marginArray->MdcaCount() == 4)
		{
			aStyle->iPadding.SetTop((*marginArray)[0]);
			aStyle->iPadding.SetRight((*marginArray)[1]);
			aStyle->iPadding.SetBottom((*marginArray)[2]);
			aStyle->iPadding.SetLeft((*marginArray)[3]);
		}

		CleanupStack::PopAndDestroy(2);
	}
}

void RenderObject::_parseBorderL(const TDesC& aDes,RenderObject* iRenderObj)
{
	HtmlStyle* aStyle = iRenderObj->GetHtmlStyle();
	if(!aStyle)
		return;

	TBuf<16> buf = _L("border-left-width:");
	TInt pos = 0;
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetLeft(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-left-style:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetLeft(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-left-color:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetLeft(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-top-width:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetTop(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-top-style:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetTop(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-top-color:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetTop(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-right-width:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetRight(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-right-style:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetRight(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-right-color:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetRight(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-bottom-width:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetBottom(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-bottom-style:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetBottom(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-bottom-color:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetBottom(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-width:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		SetBordersL(aDes.Mid(pos+buf.Length()),aStyle);

		return;
	}

	buf = _L("border-height:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		SetBordersL(aDes.Mid(pos+buf.Length()),aStyle);

		return;
	}

	buf = _L("border-color:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		SetBordersL(aDes.Mid(pos+buf.Length()),aStyle);

		return;
	}

	buf = _L("border-left:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetLeft(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-right:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetRight(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-top:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetTop(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border-bottom:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetBottom(aDes.Mid(pos+buf.Length()));
		return;
	}

	buf = _L("border:");
	if((pos =aDes.Find(buf)) != KErrNotFound)
	{
		aStyle->iBorder.SetLeft(aDes.Mid(pos+buf.Length()));
		aStyle->iBorder.SetRight(aDes.Mid(pos+buf.Length()));
		aStyle->iBorder.SetTop(aDes.Mid(pos+buf.Length()));
		aStyle->iBorder.SetBottom(aDes.Mid(pos+buf.Length()));
		return;
	}
}

void RenderObject::SetBordersL(const TDesC& aDes,HtmlStyle* aStyle)
{
	CStringUtility* strUtil = CStringUtility::NewL(aDes);
	CleanupStack::PushL(strUtil);

	TBuf<1> sel = _L(" ");
	CDesCArray* borderArray = new(ELeave) CDesCArraySeg(4);
	CleanupStack::PushL(borderArray);
	
	while (!strUtil->Eof())
	{
		TPtrC ptr = strUtil->NextToken(sel);

		borderArray->AppendL(ptr);
	}

	if(borderArray->MdcaCount() == 1)
	{
		aStyle->iBorder.SetLeft((*borderArray)[0]);
		aStyle->iBorder.SetRight((*borderArray)[0]);
		aStyle->iBorder.SetTop((*borderArray)[0]);
		aStyle->iBorder.SetBottom((*borderArray)[0]);
	}
	else if(borderArray->MdcaCount() == 2)
	{
		aStyle->iBorder.SetTop((*borderArray)[0]);
		aStyle->iBorder.SetRight((*borderArray)[1]);
		aStyle->iBorder.SetBottom((*borderArray)[0]);
		aStyle->iBorder.SetLeft((*borderArray)[1]);
	}
	else if(borderArray->MdcaCount() == 3)
	{
		aStyle->iBorder.SetTop((*borderArray)[0]);
		aStyle->iBorder.SetRight((*borderArray)[1]);
		aStyle->iBorder.SetBottom((*borderArray)[2]);
		aStyle->iBorder.SetLeft((*borderArray)[1]);
	}
	else if(borderArray->MdcaCount() == 4)
	{
		aStyle->iBorder.SetTop((*borderArray)[0]);
		aStyle->iBorder.SetRight((*borderArray)[1]);
		aStyle->iBorder.SetBottom((*borderArray)[2]);
		aStyle->iBorder.SetLeft((*borderArray)[3]);
	}

//	borderArray.Clear();

	CleanupStack::PopAndDestroy(2);
}

void RenderObject::_parseWidth(const TDesC& aDes,RenderObject* iRenderObj)
{
	HtmlStyle* aStyle = iRenderObj->GetHtmlStyle();
	if(!aStyle)
		return;

	aStyle->iWidth = aDes;
}

void RenderObject::_parseHeight(const TDesC& aDes,RenderObject* iRenderObj)
{
	HtmlStyle* aStyle = iRenderObj->GetHtmlStyle();
	if(!aStyle)
		return;

	aStyle->iHeight = aDes;
}

void RenderObject::AppendChildL(RenderObject* iObj)
	{
	if(!iObj)
		return;
	
	if(GetHtmlStyle()->iDisplay == HtmlStyle::DisplayBlock)
		{
		if(iObj->GetHtmlStyle()->iDisplay == HtmlStyle::DisplayBlock)
			{
			AppendChildSimply(iObj);
			}
		else if(iObj->GetHtmlStyle()->iDisplay == HtmlStyle::DisplayInline)
			{
			if(iObj->GetRenderType() != RenderObject::RTAnonymousBlock)
				{
				//创建Anonymous Block
				RenderObject* anonymousBlock = RenderObject::CreateAnonymousObjectL();
				CleanupStack::PushL(anonymousBlock);
				
				anonymousBlock->AppendChildSimply(iObj);
				AppendChildSimply(anonymousBlock);
				
				CleanupStack::Pop(1);
				}
			else
				AppendChildSimply(iObj);
			
			}
		}
	else if(GetHtmlStyle()->iDisplay == HtmlStyle::DisplayInline)
		{
		if(iObj->GetHtmlStyle()->iDisplay == HtmlStyle::DisplayBlock)
			{
			
			}
		else if(iObj->GetHtmlStyle()->iDisplay == HtmlStyle::DisplayInline)
			{
			AppendChildSimply(iObj);
			}
		}
	else
		{
		
		}
	}

RenderObject* RenderObject::CreateAnonymousObjectL()
	{
	RenderObject* iRetObj = new(ELeave) RenderObject;
	iRetObj->iRenderType = RTAnonymousBlock;
	
	return iRetObj;
	}

void RenderObject::AppendChildSimply(RenderObject* aChild)
	{
	if(!iFirstChild)
		{
		iFirstChild = iLastChild = aChild;
		aChild->SetParentRenderObject(this);
		iChildNodeCount++;
		}
	else
		{
		iLastChild->SetNextSibling(aChild);
		aChild->SetPreSibling(iLastChild);
		iLastChild = aChild;
		aChild->SetParentRenderObject(this);
		iChildNodeCount++;
		}
	}
}
